﻿using MQTTnet;
using MQTTnet.Formatter;
using MQTTnet.Protocol;
using System.Buffers;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace MQTT.Client.Longma
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // 定义MQTT客户端
        private IMqttClient client;

        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnConn_Click(object sender, RoutedEventArgs e)
        {
            client = new MqttClientFactory().CreateMqttClient();

            // 配置MQTT客户端选项
            MqttClientOptions options = new MqttClientOptionsBuilder()
                .WithProtocolVersion(MqttProtocolVersion.V500) // 设置MQTT协议版本为5.0,默认为5.0
                .WithTcpServer(txtIP.Text, int.Parse(txtPort.Text)) // 连接服务器地址和端口号
                .WithCredentials(txtUserName.Text, txtPassword.Password) // 设置用户名和密码
                .WithClientId(txtClientId.Text) // 设置客户端ID (客户端id可以不写，会自动生成一个随机的)
                                                //.WithCleanSession(false)  //WithCleanSession和WithCleanStart只是MQTT版本的不同而已，功能是一样的。
                                                //.WithCleanStart(false) // 设置为true表示每次连接服务器都当作一个新的连接，false表示服务器会保存客户端会话。默认值为true
                                                //.WithSessionExpiryInterval(7200) // 设置会话过期时间，单位为秒。默认值为0，表示会话永不过期
                                                // 遗嘱
                                                //.WithWillTopic("test/offline") // 设置遗嘱主题，当客户端异常断开连接时，服务器会发布遗嘱消息到该主题
                                                //.WithWillPayload("I'm offline") // 设置遗嘱消息的内容
                                                //.WithWillQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce) // 设置遗嘱消息的服务质量等级，默认为0 (0, 1, 2)
                                                //.WithKeepAlivePeriod(TimeSpan.FromSeconds(60)) // 设置心跳过期时间
                                                //.WithNoKeepAlive() // 设置为表示不发送心跳包
                .Build();
            /**
             * 
            /// <summary>
            ///     Clean session is used in MQTT versions below 5.0.0. It is the same as setting "CleanStart".
            /// </summary>
            public MqttClientOptionsBuilder WithCleanSession(bool value = true)
            {
                _options.CleanSession = value;
                return this;
            }

            /// <summary>
            ///     Clean start is used in MQTT versions 5.0.0 and higher. It is the same as setting "CleanSession".
            /// </summary>
            public MqttClientOptionsBuilder WithCleanStart(bool value = true)
            {
                _options.CleanSession = value;
                return this;
            }
             * 
             */

            MqttClientConnectResult result = await client.ConnectAsync(options);

            // 连接成功
            if (result.ResultCode == MqttClientConnectResultCode.Success)
            {
                BtnConn.Visibility = Visibility.Collapsed; // 隐藏连接按钮
                BtnDisConn.Visibility = Visibility.Visible; // 显示断开按钮

                AppendTxt("连接成功", Colors.Green);

                // 注册消息接收事件
                client.ApplicationMessageReceivedAsync += Client_ApplicationMessageReceivedAsync;

                // todo:这里可以连接成功后，到数据库获取ClientId,进行自动恢复订阅
                // client.SubscribeAsync();
            }

        }

        /// <summary>
        /// 接收订阅的消息执行的业务
        /// </summary>
        /// <param name="arg"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private Task Client_ApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg)
        {
            // 客户端id
            string clientId = arg.ClientId;
            // 主题
            string topic = arg.ApplicationMessage.Topic;
            // 载荷
            string content = Encoding.UTF8.GetString(arg.ApplicationMessage.Payload.ToArray());

            AppendTxt($"接收到的消息:{content}", Colors.Green);

            return Task.CompletedTask;
        }

        /// <summary>
        /// 断开
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnDisConn_Click(object sender, RoutedEventArgs e)
        {
            if (client != null && client.IsConnected)
            {
                await client.DisconnectAsync();

                BtnConn.Visibility = Visibility.Visible;  // 显示连接按钮
                BtnDisConn.Visibility = Visibility.Collapsed; // 隐藏断开按钮


                AppendTxt("连接已断开", Colors.Red);
            }
        }

        FlowDocument doc = new FlowDocument();
        /// <summary>
        /// 追加信息到richtextbox结尾
        /// </summary>
        /// <param name="txt"></param>
        /// <param name="txtColor">文字颜色</param>
        private void AppendTxt(string txt, Color txtColor)
        {
            Dispatcher.Invoke(() =>
            {
                var p = new Paragraph(); // Paragraph 类似于 html 的 P 标签
                var r = new Run($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} {txt}"); // Run 是一个 Inline 的标签
                p.Inlines.Add(r);
                p.Foreground = new SolidColorBrush(txtColor);//设置字体颜色

                doc.Blocks.Add(p);
                txtShowContent.Document = doc;
                txtShowContent.ScrollToEnd();
            });
        }

        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnSub_Click(object sender, RoutedEventArgs e)
        {
            if (client != null && client.IsConnected)
            {
                MqttClientSubscribeResult result = await client.SubscribeAsync(txtSubTopic.Text, MqttQualityOfServiceLevel.ExactlyOnce);
                if (string.IsNullOrWhiteSpace(result.ReasonString))
                {
                    AppendTxt($"订阅主题:{txtSubTopic.Text}成功", Colors.Green);
                }
                else
                {
                    AppendTxt($"订阅主题:{txtSubTopic.Text}失败", Colors.Red);
                }

            }
        }

        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private async void BtnPub_Click(object sender, RoutedEventArgs e)
        {
            if (client != null && client.IsConnected)
            {
                MqttApplicationMessage msg = new MqttApplicationMessageBuilder()
                    .WithTopic(txtPubTopic.Text)
                    .WithPayload(txtPubContent.Text)
                    //.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.ExactlyOnce) // 服务质量等级 (0, 1, 2)
                    //.WithRetainFlag(false) // 发布的消息是否保留消息
                    //.WithUserProperty("name", "zhangsan") // 用户属性，可以设置多个键值对，最大长度为65535字节
                    .Build();

                MqttClientPublishResult result = await client.PublishAsync(msg);

                if (result.IsSuccess)
                {
                    AppendTxt($"给主题:{txtPubTopic.Text},发布消息{txtPubContent.Text}", Colors.Green);
                }
                else
                {
                    AppendTxt($"发布失败:{result.ReasonCode},{result.ReasonString}", Colors.Red);
                }
            }
        }
    }
}